From 0a706cbe6973b0e3c5f7c9de27376725680fc5db Mon Sep 17 00:00:00 2001 From: tsteven4 Date: Mon, 15 Oct 2018 11:00:54 -0600 Subject: [PATCH] eliminate queues in csv style handling. also: fix bug with style option encoding. pass some parameters by const reference. eliminate some unused time fiddling. --- csv_util.cc | 360 ++++++++++++++++++++++++---------------------------- csv_util.h | 51 ++++---- xcsv.cc | 92 +++----------- 3 files changed, 211 insertions(+), 292 deletions(-) diff --git a/csv_util.cc b/csv_util.cc index ba1685ed2..d35227e3c 100644 --- a/csv_util.cc +++ b/csv_util.cc @@ -20,9 +20,11 @@ */ -#include -#include -#include +#include // for QChar +#include // for QDateTime, QDate +#include // for QString, QCharRef +#include // for QTextStream +#include // for foreach #include "csv_util.h" #include "defs.h" @@ -713,8 +715,6 @@ void xcsv_file_init(void) xcsv_file.field_encloser = QString(); xcsv_file.record_delimiter = QString(); xcsv_file.badchars = QString(); - xcsv_file.ifield_ct = 0; - xcsv_file.ofield_ct = 0; xcsv_file.file = nullptr; xcsv_file.stream = nullptr; xcsv_file.codec = nullptr; @@ -725,12 +725,8 @@ void xcsv_file_init(void) xcsv_file.prologue.clear(); xcsv_file.epilogue.clear(); - QUEUE_INIT(&xcsv_file.ifield); - /* ofield is alloced to allow pointing back at ifields - * where applicable. - */ - xcsv_file.ofield = (queue*) xcalloc(sizeof(queue), 1); - QUEUE_INIT(xcsv_file.ofield); + xcsv_file.ifields.clear(); + xcsv_file.ofields.clear(); /* * Provide a sane default for CSV _files_. */ @@ -742,25 +738,20 @@ void xcsv_file_init(void) XcsvFile::XcsvFile() { is_internal = false; - ifield_ct = ofield_ct = 0; extension = nullptr; // xcsv_file_init(); } -static void validate_fieldmap(const field_map_t* fmp, bool is_output) { - QString qkey = fmp->key; - QString qval = fmp->val; - QString qprintfc = fmp->printfc; - - if (qkey.isEmpty()) { +static void validate_fieldmap(const field_map& fmp, bool is_output) { + if (fmp.key.isEmpty()) { Fatal() << MYNAME << ": xcsv style is missing" << (is_output ? "output" : "input") << "field type."; } - if (!fmp->val) { - Fatal() << MYNAME << ": xcsv style" << qkey << "is missing default."; + if (fmp.val.isNull()) { + Fatal() << MYNAME << ": xcsv style" << fmp.key.constData() << "is missing default."; } - if (is_output && !fmp->printfc) { - Fatal() << MYNAME << ": xcsv style" << qkey << "output is missing format specifier."; + if (is_output && fmp.printfc.isNull()) { + Fatal() << MYNAME << ": xcsv style" << fmp.key.constData() << "output is missing format specifier."; } } @@ -769,19 +760,18 @@ static void validate_fieldmap(const field_map_t* fmp, bool is_output) { /* usage: xcsv_ifield_add("DESCRIPTION", "", "%s") */ /*****************************************************************************/ void -xcsv_ifield_add(const char* key, const char* val, const char* pfc) +xcsv_ifield_add(const QString& qkey, const QString& qval, const QString& qpfc) { - field_map_t* fmp = (field_map_t*) xcalloc(sizeof(*fmp), 1); - struct xt_mapping* xm = Perfect_Hash::in_word_set(key, strlen(key)); + QByteArray key = qkey.toUtf8(); + QByteArray val = qval.toUtf8(); + QByteArray pfc = qpfc.toUtf8(); - fmp->key = key; - fmp->hashed_key = xm ? xm->xt_token : -1; - fmp->val = val; - fmp->printfc = pfc; + struct xt_mapping* xm = Perfect_Hash::in_word_set(key.constData(), strlen(key.constData())); + + field_map fmp(key, val, pfc, xm ? xm->xt_token : -1); validate_fieldmap(fmp, false); - ENQUEUE_TAIL(&xcsv_file.ifield, &fmp->Q); - xcsv_file.ifield_ct++; + xcsv_file.ifields.append(fmp); } /*****************************************************************************/ @@ -789,20 +779,18 @@ xcsv_ifield_add(const char* key, const char* val, const char* pfc) /* usage: xcsv_ofield_add("LAT_DECIMAL", "", "%08.5lf") */ /*****************************************************************************/ void -xcsv_ofield_add(const char* key, const char* val, const char* pfc, int options) +xcsv_ofield_add(const QString& qkey, const QString& qval, const QString& qpfc, unsigned options) { - field_map_t* fmp = (field_map_t*) xcalloc(sizeof(*fmp), 1); - struct xt_mapping* xm = Perfect_Hash::in_word_set(key, strlen(key)); - - fmp->key = key; - fmp->hashed_key = xm ? xm->xt_token : -1; - fmp->val = val; - fmp->printfc = pfc; - fmp->options = options; + QByteArray key = qkey.toUtf8(); + QByteArray val = qval.toUtf8(); + QByteArray pfc = qpfc.toUtf8(); + + struct xt_mapping* xm = Perfect_Hash::in_word_set(key.constData(), strlen(key.constData())); + + field_map fmp(key, val, pfc, xm ? xm->xt_token : -1, options); validate_fieldmap(fmp, true); - ENQUEUE_TAIL(xcsv_file.ofield, &fmp->Q); - xcsv_file.ofield_ct++; + xcsv_file.ofields.append(fmp); } /*****************************************************************************/ @@ -810,7 +798,7 @@ xcsv_ofield_add(const char* key, const char* val, const char* pfc, int options) /* usage: xcsv_prologue_add("Four score and seven years ago today,") */ /*****************************************************************************/ void -xcsv_prologue_add(QString prologue) +xcsv_prologue_add(const QString& prologue) { xcsv_file.prologue.append(prologue); } @@ -820,7 +808,7 @@ xcsv_prologue_add(QString prologue) /* usage: xcsv_epilogue_add("shall not perish from the earth.") */ /*****************************************************************************/ void -xcsv_epilogue_add(QString epilogue) +xcsv_epilogue_add(const QString& epilogue) { xcsv_file.epilogue.append(epilogue); } @@ -968,20 +956,20 @@ gmsd_init(Waypoint* wpt) /* usage: xcsv_parse_val("-123.34", *waypt, *field_map) */ /*****************************************************************************/ static void -xcsv_parse_val(const char* s, Waypoint* wpt, const field_map_t* fmp, +xcsv_parse_val(const char* s, Waypoint* wpt, const field_map& fmp, route_head** trk) { const char* enclosure = ""; geocache_data* gc_data = nullptr; - if (!fmp->printfc) { - fatal(MYNAME ": xcsv style '%s' is missing format specifier", fmp->key); + if (fmp.printfc.isNull()) { + fatal(MYNAME ": xcsv style '%s' is missing format specifier", fmp.key.constData()); } - if (0 == strcmp(fmp->printfc, "\"%s\"")) { + if (0 == strcmp(fmp.printfc.constData(), "\"%s\"")) { enclosure = "\""; } - switch (fmp->hashed_key) { + switch (fmp.hashed_key) { case XT_IGNORE: /* IGNORE -- Categorically ignore this... */ break; @@ -1190,21 +1178,21 @@ xcsv_parse_val(const char* s, Waypoint* wpt, const field_map_t* fmp, wpt->SetCreationTime(yyyymmdd_to_time(s)); break; case XT_GMT_TIME: - wpt->SetCreationTime(sscanftime(s, fmp->printfc, 1)); + wpt->SetCreationTime(sscanftime(s, fmp.printfc.constData(), 1)); break; case XT_LOCAL_TIME: if (ugetenv("GPSBABEL_FREEZE_TIME").isNull()) { - wpt->creation_time += sscanftime(s, fmp->printfc, 0); + wpt->creation_time += sscanftime(s, fmp.printfc.constData(), 0); } else { /* Force constant time zone for test */ - wpt->creation_time += sscanftime(s, fmp->printfc, 1); + wpt->creation_time += sscanftime(s, fmp.printfc.constData(), 1); } break; /* Useful when time and date are in separate fields GMT / Local offset is handled by the two cases above */ case XT_HMSG_TIME: case XT_HMSL_TIME: - wpt->creation_time += addhms(s, fmp->printfc); + wpt->creation_time += addhms(s, fmp.printfc.constData()); break; case XT_ISO_TIME: case XT_ISO_TIME_MS: @@ -1373,12 +1361,12 @@ xcsv_parse_val(const char* s, Waypoint* wpt, const field_map_t* fmp, } break; case -1: - if (strncmp(fmp->key, "LON_10E", 7) == 0) { - wpt->longitude = atof(s) / pow(10.0, atof(fmp->key+7)); - } else if (strncmp(fmp->key, "LAT_10E", 7) == 0) { - wpt->latitude = atof(s) / pow(10.0, atof(fmp->key+7)); + if (strncmp(fmp.key.constData(), "LON_10E", 7) == 0) { + wpt->longitude = atof(s) / pow(10.0, atof(fmp.key.constData()+7)); + } else if (strncmp(fmp.key.constData(), "LAT_10E", 7) == 0) { + wpt->latitude = atof(s) / pow(10.0, atof(fmp.key.constData()+7)); } else { - warning(MYNAME ": Unknown style directive: %s\n", fmp->key); + warning(MYNAME ": Unknown style directive: %s\n", fmp.key.constData()); } break; @@ -1447,23 +1435,20 @@ xcsv_data_read(void) s = csv_lineparse(s, CSTR(xcsv_file.field_delimiter), CSTR(xcsv_file.field_encloser), linecount); - if (QUEUE_EMPTY(&xcsv_file.ifield)) { + if (xcsv_file.ifields.isEmpty()) { fatal(MYNAME ": attempt to read, but style '%s' has no IFIELDs in it.\n", CSTR(xcsv_file.description)? CSTR(xcsv_file.description) : "unknown"); } - /* reset the ifield queue */ - queue* elem = QUEUE_FIRST(&xcsv_file.ifield); + int ifield_idx = 0; /* now rip the line apart, advancing the queue for each tear * off the beginning of buff since there's no index into queue. */ while (s) { - field_map_t* fmp = reinterpret_cast(elem); + const field_map& fmp = xcsv_file.ifields.at(ifield_idx++); xcsv_parse_val(s, wpt_tmp, fmp, &trk); - elem = QUEUE_NEXT(elem); - - if (elem == &xcsv_file.ifield) { + if (ifield_idx >= xcsv_file.ifields.size()) { /* we've wrapped the queue. so stop parsing! */ while (s) { s = csv_lineparse(nullptr, "\xff","",linecount); @@ -1551,7 +1536,6 @@ static void xcsv_waypt_pr(const Waypoint* wpt) { QString buff; - queue* elem, *tmp; double latitude, longitude; int32 utmz; double utme, utmn; @@ -1609,7 +1593,7 @@ xcsv_waypt_pr(const Waypoint* wpt) } int i = 0; - QUEUE_FOR_EACH(xcsv_file.ofield, elem, tmp) { + for (const auto& fmp : xcsv_file.ofields) { double lat = latitude; double lon = longitude; /* @@ -1620,39 +1604,37 @@ xcsv_waypt_pr(const Waypoint* wpt) */ int field_is_unknown = 0; - field_map_t* fmp = reinterpret_cast(elem); - - if ((i != 0) && !(fmp->options & OPTIONS_NODELIM)) { + if ((i != 0) && !(fmp.options & OPTIONS_NODELIM)) { *xcsv_file.stream << write_delimiter; } - if (fmp->options & OPTIONS_ABSOLUTE) { + if (fmp.options & OPTIONS_ABSOLUTE) { lat = fabs(lat); lon = fabs(lon); } i++; - switch (fmp->hashed_key) { + switch (fmp.hashed_key) { case XT_IGNORE: /* IGNORE -- Write the char printf conversion */ - buff = QString().sprintf(fmp->printfc, ""); + buff = QString().sprintf(fmp.printfc.constData(), ""); break; case XT_INDEX: - buff = QString().sprintf(fmp->printfc, waypt_out_count + atoi(fmp->val)); + buff = QString().sprintf(fmp.printfc.constData(), waypt_out_count + atoi(fmp.val.constData())); break; case XT_CONSTANT: { - auto cp = xcsv_get_char_from_constant_table(fmp->val); + auto cp = xcsv_get_char_from_constant_table(fmp.val.constData()); if (!cp.isEmpty()) { - buff = QString().sprintf(fmp->printfc, CSTR(cp)); + buff = QString().sprintf(fmp.printfc.constData(), CSTR(cp)); } else { - buff = QString().sprintf(fmp->printfc, fmp->val); + buff = QString().sprintf(fmp.printfc.constData(), fmp.val.constData()); } } break; case XT_SHORTNAME: - buff = QString().sprintf(fmp->printfc, - shortname.isEmpty() ? fmp->val : CSTR(shortname)); + buff = QString().sprintf(fmp.printfc.constData(), + shortname.isEmpty() ? fmp.val.constData() : CSTR(shortname)); break; case XT_ANYNAME: @@ -1668,19 +1650,19 @@ xcsv_waypt_pr(const Waypoint* wpt) anyname = wpt->notes; } if (anyname.isEmpty()) { - anyname = fmp->val; + anyname = fmp.val.constData(); } - buff = QString().sprintf(fmp->printfc, CSTR(anyname)); + buff = QString().sprintf(fmp.printfc.constData(), CSTR(anyname)); } break; case XT_DESCRIPTION: - buff = QString().sprintf(fmp->printfc, - description.isEmpty() ? fmp->val : CSTR(description)); + buff = QString().sprintf(fmp.printfc.constData(), + description.isEmpty() ? fmp.val.constData() : CSTR(description)); break; case XT_NOTES: - buff = QString().sprintf(fmp->printfc, - wpt->notes.isEmpty() ? fmp->val : CSTR(wpt->notes)); + buff = QString().sprintf(fmp.printfc.constData(), + wpt->notes.isEmpty() ? fmp.val.constData() : CSTR(wpt->notes)); break; case XT_URL: { if (xcsv_urlbase) { @@ -1688,106 +1670,106 @@ xcsv_waypt_pr(const Waypoint* wpt) } if (wpt->HasUrlLink()) { UrlLink l = wpt->GetUrlLink(); - buff += QString().sprintf(fmp->printfc, CSTR(l.url_)); + buff += QString().sprintf(fmp.printfc.constData(), CSTR(l.url_)); } else { - buff += QString().sprintf(fmp->printfc, fmp->val && *fmp->val ? fmp->val : "\"\""); + buff += QString().sprintf(fmp.printfc.constData(), fmp.val.constData() && *fmp.val.constData() ? fmp.val.constData() : "\"\""); } } break; case XT_URL_LINK_TEXT: if (wpt->HasUrlLink()) { UrlLink l = wpt->GetUrlLink(); - buff = QString().sprintf(fmp->printfc, - !l.url_link_text_.isEmpty() ? CSTR(l.url_link_text_) : fmp->val); + buff = QString().sprintf(fmp.printfc.constData(), + !l.url_link_text_.isEmpty() ? CSTR(l.url_link_text_) : fmp.val.constData()); } break; case XT_ICON_DESCR: - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), (!wpt->icon_descr.isNull()) ? - CSTR(wpt->icon_descr) : fmp->val); + CSTR(wpt->icon_descr) : fmp.val.constData()); break; /* LATITUDE CONVERSION***********************************************/ case XT_LAT_DECIMAL: /* latitude as a pure decimal value */ - buff = QString().sprintf(fmp->printfc, lat); + buff = QString().sprintf(fmp.printfc.constData(), lat); break; case XT_LAT_DECIMALDIR: /* latitude as a decimal value with N/S after it */ - buff = QString().sprintf(fmp->printfc, fabs(lat), + buff = QString().sprintf(fmp.printfc.constData(), fabs(lat), LAT_DIR(lat)); break; case XT_LAT_DIRDECIMAL: /* latitude as a decimal value with N/S before it */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), LAT_DIR(lat), fabs(lat)); break; case XT_LAT_INT32DEG: /* latitude as an integer offset from 0 degrees */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), dec_to_intdeg(lat)); break; case XT_LAT_DDMMDIR: /*latitude as (degrees * 100) + decimal minutes, with N/S after it */ - buff = dec_to_human(fmp->printfc, "SN", degrees2ddmm(lat)); + buff = dec_to_human(fmp.printfc.constData(), "SN", degrees2ddmm(lat)); break; case XT_LAT_HUMAN_READABLE: - buff = dec_to_human(fmp->printfc, "SN", lat); + buff = dec_to_human(fmp.printfc.constData(), "SN", lat); break; case XT_LAT_NMEA: - buff = QString().sprintf(fmp->printfc, degrees2ddmm(lat)); + buff = QString().sprintf(fmp.printfc.constData(), degrees2ddmm(lat)); break; // case XT_LAT_10E is handled outside the switch. /* LONGITUDE CONVERSIONS*********************************************/ case XT_LON_DECIMAL: /* longitude as a pure decimal value */ - buff = QString().sprintf(fmp->printfc, lon); + buff = QString().sprintf(fmp.printfc.constData(), lon); break; case XT_LON_DECIMALDIR: /* latitude as a decimal value with N/S after it */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), fabs(lon), LON_DIR(lon)); break; case XT_LON_DIRDECIMAL: /* latitude as a decimal value with N/S before it */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), LON_DIR(lon), fabs(lon)); break; case XT_LON_INT32DEG: /* longitudee as an integer offset from 0 degrees */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), dec_to_intdeg(lon)); break; case XT_LON_DDMMDIR: /* longidute as (degrees * 100) + decimal minutes, with W/E after it*/ - buff = dec_to_human(fmp->printfc, "WE", degrees2ddmm(lon)); + buff = dec_to_human(fmp.printfc.constData(), "WE", degrees2ddmm(lon)); break; case XT_LON_HUMAN_READABLE: - buff = dec_to_human(fmp->printfc, "WE", lon); + buff = dec_to_human(fmp.printfc.constData(), "WE", lon); break; case XT_LATLON_HUMAN_READABLE: - buff = dec_to_human(fmp->printfc, "SN", lat); + buff = dec_to_human(fmp.printfc.constData(), "SN", lat); buff += " "; - buff += dec_to_human(fmp->printfc, "WE", lon); + buff += dec_to_human(fmp.printfc.constData(), "WE", lon); // Tidy up leading, trailing, middle whitespace. buff = buff.simplified(); break; case XT_LON_NMEA: - buff = QString().sprintf(fmp->printfc, degrees2ddmm(lon)); + buff = QString().sprintf(fmp.printfc.constData(), degrees2ddmm(lon)); break; // case XT_LON_10E is handled outside the switch. /* DIRECTIONS *******************************************************/ case XT_LAT_DIR: /* latitude N/S as a char */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), LAT_DIR(lat)); break; case XT_LON_DIR: /* longitude E/W as a char */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), LON_DIR(lon)); break; @@ -1798,7 +1780,7 @@ xcsv_waypt_pr(const Waypoint* wpt) if (! GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map)) fatal(MYNAME ": Position (%.5f/%.5f) outside of BNG.\n", wpt->latitude, wpt->longitude); - buff = QString().sprintf(fmp->printfc, map, (int)(east + 0.5), (int)(north + 0.5)); + buff = QString().sprintf(fmp.printfc.constData(), map, (int)(east + 0.5), (int)(north + 0.5)); } break; case XT_UTM: { @@ -1807,18 +1789,18 @@ xcsv_waypt_pr(const Waypoint* wpt) &utme, &utmn, &utmz, &utmzc); snprintf(tbuf, sizeof(tbuf), "%d%c %6.0f %7.0f", utmz, utmzc, utme, utmn); - buff = QString().sprintf(fmp->printfc, tbuf); + buff = QString().sprintf(fmp.printfc.constData(), tbuf); } break; case XT_UTM_ZONE: GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, &utme, &utmn, &utmz, &utmzc); - buff = QString().sprintf(fmp->printfc, utmz); + buff = QString().sprintf(fmp.printfc.constData(), utmz); break; case XT_UTM_ZONEC: GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, &utme, &utmn, &utmz, &utmzc); - buff = QString().sprintf(fmp->printfc, utmzc); + buff = QString().sprintf(fmp.printfc.constData(), utmzc); break; case XT_UTM_ZONEF: { char tbuf[10]; @@ -1826,29 +1808,29 @@ xcsv_waypt_pr(const Waypoint* wpt) &utme, &utmn, &utmz, &utmzc); tbuf[0] = 0; snprintf(tbuf, sizeof(tbuf), "%d%c", utmz, utmzc); - buff = QString().sprintf(fmp->printfc, tbuf); + buff = QString().sprintf(fmp.printfc.constData(), tbuf); } break; case XT_UTM_NORTHING: GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, &utme, &utmn, &utmz, &utmzc); - buff = QString().sprintf(fmp->printfc, utmn); + buff = QString().sprintf(fmp.printfc.constData(), utmn); break; case XT_UTM_EASTING: GPS_Math_WGS84_To_UTM_EN(wpt->latitude, wpt->longitude, &utme, &utmn, &utmz, &utmzc); - buff = QString().sprintf(fmp->printfc, utme); + buff = QString().sprintf(fmp.printfc.constData(), utme); break; /* ALTITUDE CONVERSIONS**********************************************/ case XT_ALT_FEET: /* altitude in feet as a decimal value */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), METERS_TO_FEET(wpt->altitude)); break; case XT_ALT_METERS: /* altitude in meters as a decimal value */ - buff = QString().sprintf(fmp->printfc, + buff = QString().sprintf(fmp.printfc.constData(), wpt->altitude); break; @@ -1858,71 +1840,71 @@ xcsv_waypt_pr(const Waypoint* wpt) case XT_PATH_DISTANCE_MILES: /* path (route/track) distance in miles */ if (wpt->odometer_distance) { - buff = QString().sprintf(fmp->printfc, METERS_TO_MILES(wpt->odometer_distance)); + buff = QString().sprintf(fmp.printfc.constData(), METERS_TO_MILES(wpt->odometer_distance)); } else { - buff = QString().sprintf(fmp->printfc, pathdist); + buff = QString().sprintf(fmp.printfc.constData(), pathdist); } break; case XT_PATH_DISTANCE_METERS: /* path (route/track) distance in meters */ if (wpt->odometer_distance) { - buff = QString().sprintf(fmp->printfc, wpt->odometer_distance); + buff = QString().sprintf(fmp.printfc.constData(), wpt->odometer_distance); } else { - buff = QString().sprintf(fmp->printfc, MILES_TO_METERS(pathdist)); + buff = QString().sprintf(fmp.printfc.constData(), MILES_TO_METERS(pathdist)); } break; case XT_PATH_DISTANCE_KM: /* path (route/track) distance in kilometers */ if (wpt->odometer_distance) { - buff = QString().sprintf(fmp->printfc, wpt->odometer_distance / 1000.0); + buff = QString().sprintf(fmp.printfc.constData(), wpt->odometer_distance / 1000.0); } else { - buff = QString().sprintf(fmp->printfc, MILES_TO_METERS(pathdist) / 1000.0); + buff = QString().sprintf(fmp.printfc.constData(), MILES_TO_METERS(pathdist) / 1000.0); } break; case XT_PATH_SPEED: - buff = QString().sprintf(fmp->printfc, wpt->speed); + buff = QString().sprintf(fmp.printfc.constData(), wpt->speed); break; case XT_PATH_SPEED_KPH: - buff = QString().sprintf(fmp->printfc, MPS_TO_KPH(wpt->speed)); + buff = QString().sprintf(fmp.printfc.constData(), MPS_TO_KPH(wpt->speed)); break; case XT_PATH_SPEED_MPH: - buff = QString().sprintf(fmp->printfc, MPS_TO_MPH(wpt->speed)); + buff = QString().sprintf(fmp.printfc.constData(), MPS_TO_MPH(wpt->speed)); break; case XT_PATH_SPEED_KNOTS: - buff = QString().sprintf(fmp->printfc, MPS_TO_KNOTS(wpt->speed)); + buff = QString().sprintf(fmp.printfc.constData(), MPS_TO_KNOTS(wpt->speed)); break; case XT_PATH_COURSE: - buff = QString().sprintf(fmp->printfc, wpt->course); + buff = QString().sprintf(fmp.printfc.constData(), wpt->course); break; /* HEART RATE CONVERSION***********************************************/ case XT_HEART_RATE: - buff = QString().sprintf(fmp->printfc, wpt->heartrate); + buff = QString().sprintf(fmp.printfc.constData(), wpt->heartrate); break; /* CADENCE CONVERSION***********************************************/ case XT_CADENCE: - buff = QString().sprintf(fmp->printfc, wpt->cadence); + buff = QString().sprintf(fmp.printfc.constData(), wpt->cadence); break; /* POWER CONVERSION***********************************************/ case XT_POWER: - buff = QString().sprintf(fmp->printfc, wpt->power); + buff = QString().sprintf(fmp.printfc.constData(), wpt->power); break; case XT_TEMPERATURE: - buff = QString().sprintf(fmp->printfc, wpt->temperature); + buff = QString().sprintf(fmp.printfc.constData(), wpt->temperature); break; case XT_TEMPERATURE_F: - buff = QString().sprintf(fmp->printfc, CELSIUS_TO_FAHRENHEIT(wpt->temperature)); + buff = QString().sprintf(fmp.printfc.constData(), CELSIUS_TO_FAHRENHEIT(wpt->temperature)); break; /* TIME CONVERSIONS**************************************************/ case XT_EXCEL_TIME: /* creation time as an excel (double) time */ - buff = QString().sprintf(fmp->printfc, TIMET_TO_EXCEL(wpt->GetCreationTime().toTime_t())); + buff = QString().sprintf(fmp.printfc.constData(), TIMET_TO_EXCEL(wpt->GetCreationTime().toTime_t())); break; case XT_TIMET_TIME: /* time as a time_t variable */ { time_t tt = wpt->GetCreationTime().toTime_t(); - buff = QString().sprintf(fmp->printfc, tt); + buff = QString().sprintf(fmp.printfc.constData(), tt); } break; @@ -1934,19 +1916,19 @@ xcsv_waypt_pr(const Waypoint* wpt) } break; case XT_YYYYMMDD_TIME: - buff = QString().sprintf(fmp->printfc, time_to_yyyymmdd(wpt->GetCreationTime())); + buff = QString().sprintf(fmp.printfc.constData(), time_to_yyyymmdd(wpt->GetCreationTime())); break; case XT_GMT_TIME: - buff = writetime(fmp->printfc, wpt->GetCreationTime(), true); + buff = writetime(fmp.printfc.constData(), wpt->GetCreationTime(), true); break; case XT_LOCAL_TIME: - buff = writetime(fmp->printfc, wpt->GetCreationTime(), false); + buff = writetime(fmp.printfc.constData(), wpt->GetCreationTime(), false); break; case XT_HMSG_TIME: - buff = writehms(fmp->printfc, wpt->GetCreationTime(), 1); + buff = writehms(fmp.printfc.constData(), wpt->GetCreationTime(), 1); break; case XT_HMSL_TIME: - buff = writehms(fmp->printfc, wpt->GetCreationTime(), 0); + buff = writehms(fmp.printfc.constData(), wpt->GetCreationTime(), 0); break; case XT_ISO_TIME: buff = writetime("%Y-%m-%dT%H:%M:%SZ", wpt->GetCreationTime(), true); @@ -1955,93 +1937,93 @@ xcsv_waypt_pr(const Waypoint* wpt) buff = wpt->GetCreationTime().toPrettyString(); break; case XT_GEOCACHE_LAST_FOUND: - buff = QString().sprintf(fmp->printfc, time_to_yyyymmdd(wpt->gc_data->last_found)); + buff = QString().sprintf(fmp.printfc.constData(), time_to_yyyymmdd(wpt->gc_data->last_found)); break; /* GEOCACHE STUFF **************************************************/ case XT_GEOCACHE_DIFF: /* Geocache Difficulty as a double */ - buff = QString().sprintf(fmp->printfc, wpt->gc_data->diff / 10.0); + buff = QString().sprintf(fmp.printfc.constData(), wpt->gc_data->diff / 10.0); field_is_unknown = !wpt->gc_data->diff; break; case XT_GEOCACHE_TERR: /* Geocache Terrain as a double */ - buff = QString().sprintf(fmp->printfc, wpt->gc_data->terr / 10.0); + buff = QString().sprintf(fmp.printfc.constData(), wpt->gc_data->terr / 10.0); field_is_unknown = !wpt->gc_data->terr; break; case XT_GEOCACHE_CONTAINER: /* Geocache Container */ - buff = QString().sprintf(fmp->printfc, gs_get_container(wpt->gc_data->container)); + buff = QString().sprintf(fmp.printfc.constData(), gs_get_container(wpt->gc_data->container)); field_is_unknown = wpt->gc_data->container == gc_unknown; break; case XT_GEOCACHE_TYPE: /* Geocache Type */ - buff = QString().sprintf(fmp->printfc, gs_get_cachetype(wpt->gc_data->type)); + buff = QString().sprintf(fmp.printfc.constData(), gs_get_cachetype(wpt->gc_data->type)); field_is_unknown = wpt->gc_data->type == gt_unknown; break; case XT_GEOCACHE_HINT: - buff = QString().sprintf(fmp->printfc, CSTR(wpt->gc_data->hint)); + buff = QString().sprintf(fmp.printfc.constData(), CSTR(wpt->gc_data->hint)); field_is_unknown = !wpt->gc_data->hint.isEmpty(); break; case XT_GEOCACHE_PLACER: - buff = QString().sprintf(fmp->printfc, CSTR(wpt->gc_data->placer)); + buff = QString().sprintf(fmp.printfc.constData(), CSTR(wpt->gc_data->placer)); field_is_unknown = !wpt->gc_data->placer.isEmpty(); break; case XT_GEOCACHE_ISAVAILABLE: if (wpt->gc_data->is_available == status_false) { - buff = QString().sprintf(fmp->printfc, "False"); + buff = QString().sprintf(fmp.printfc.constData(), "False"); } else if (wpt->gc_data->is_available == status_true) { - buff = QString().sprintf(fmp->printfc, "True"); + buff = QString().sprintf(fmp.printfc.constData(), "True"); } else { - buff = QString().sprintf(fmp->printfc, "Unknown"); + buff = QString().sprintf(fmp.printfc.constData(), "Unknown"); } break; case XT_GEOCACHE_ISARCHIVED: if (wpt->gc_data->is_archived == status_false) { - buff = QString().sprintf(fmp->printfc, "False"); + buff = QString().sprintf(fmp.printfc.constData(), "False"); } else if (wpt->gc_data->is_archived == status_true) { - buff = QString().sprintf(fmp->printfc, "True"); + buff = QString().sprintf(fmp.printfc.constData(), "True"); } else { - buff = QString().sprintf(fmp->printfc, "Unknown"); + buff = QString().sprintf(fmp.printfc.constData(), "Unknown"); } break; /* Tracks and Routes ***********************************************/ case XT_TRACK_NEW: if (csv_track) { if (WAYPT_HAS(wpt,new_trkseg)) { - buff = QString().sprintf(fmp->printfc, 1); + buff = QString().sprintf(fmp.printfc.constData(), 1); } else { - buff = QString().sprintf(fmp->printfc, 0); + buff = QString().sprintf(fmp.printfc.constData(), 0); } } break; case XT_TRACK_NAME: if (csv_track) { QString r = csv_track->rte_name; - buff = QString().sprintf(fmp->printfc, NONULL(r)); + buff = QString().sprintf(fmp.printfc.constData(), NONULL(r)); } break; case XT_ROUTE_NAME: if (csv_route) { QString r = csv_route->rte_name; - buff = QString().sprintf(fmp->printfc, NONULL(r)); + buff = QString().sprintf(fmp.printfc.constData(), NONULL(r)); } break; /* GPS STUFF *******************************************************/ case XT_GPS_HDOP: - buff = QString().sprintf(fmp->printfc, wpt->hdop); + buff = QString().sprintf(fmp.printfc.constData(), wpt->hdop); field_is_unknown = !wpt->hdop; break; case XT_GPS_VDOP: - buff = QString().sprintf(fmp->printfc, wpt->vdop); + buff = QString().sprintf(fmp.printfc.constData(), wpt->vdop); field_is_unknown = !wpt->vdop; break; case XT_GPS_PDOP: - buff = QString().sprintf(fmp->printfc, wpt->pdop); + buff = QString().sprintf(fmp.printfc.constData(), wpt->pdop); field_is_unknown = !wpt->pdop; break; case XT_GPS_SAT: - buff = QString().sprintf(fmp->printfc, wpt->sat); + buff = QString().sprintf(fmp.printfc.constData(), wpt->sat); field_is_unknown = !wpt->sat; break; case XT_GPS_FIX: { @@ -2067,66 +2049,66 @@ xcsv_waypt_pr(const Waypoint* wpt) fix = "pps"; break; } - buff = QString().sprintf(fmp->printfc, fix); + buff = QString().sprintf(fmp.printfc.constData(), fix); } break; /* GMSD ************************************************************/ case XT_COUNTRY: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(country, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(country, "")); } break; case XT_STATE: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(state, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(state, "")); } break; case XT_CITY: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(city, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(city, "")); } break; case XT_POSTAL_CODE: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(postal_code, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(postal_code, "")); } break; case XT_STREET_ADDR: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(addr, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(addr, "")); } break; case XT_PHONE_NR: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(phone_nr, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(phone_nr, "")); } break; case XT_FACILITY: { garmin_fs_t* gmsd = GMSD_FIND(wpt); - buff = QString().sprintf(fmp->printfc, GMSD_GET(facility, "")); + buff = QString().sprintf(fmp.printfc.constData(), GMSD_GET(facility, "")); } break; /* specials */ case XT_FILENAME: - buff = QString().sprintf(fmp->printfc, wpt->session->filename); + buff = QString().sprintf(fmp.printfc.constData(), wpt->session->filename); break; case XT_FORMAT: - buff = QString().sprintf(fmp->printfc, wpt->session->name); + buff = QString().sprintf(fmp.printfc.constData(), wpt->session->name); break; case -1: - if (strncmp(fmp->key, "LON_10E", 7) == 0) { - buff = QString().sprintf(fmp->printfc, lon * pow(10.0, atof(fmp->key+7))); - } else if (strncmp(fmp->key, "LAT_10E", 7) == 0) { - buff = QString().sprintf(fmp->printfc, lat * pow(10.0, atof(fmp->key+7))); + if (strncmp(fmp.key.constData(), "LON_10E", 7) == 0) { + buff = QString().sprintf(fmp.printfc.constData(), lon * pow(10.0, atof(fmp.key.constData()+7))); + } else if (strncmp(fmp.key.constData(), "LAT_10E", 7) == 0) { + buff = QString().sprintf(fmp.printfc.constData(), lat * pow(10.0, atof(fmp.key.constData()+7))); } break; default: - warning(MYNAME ": Unknown style directive: %s\n", fmp->key); + warning(MYNAME ": Unknown style directive: %s\n", fmp.key.constData()); break; } QString obuff = csv_stringclean(buff, xcsv_file.badchars); - if (field_is_unknown && fmp->options & OPTIONS_OPTIONAL) { + if (field_is_unknown && fmp.options & OPTIONS_OPTIONAL) { continue; } @@ -2138,7 +2120,7 @@ xcsv_waypt_pr(const Waypoint* wpt) /* As a special case (pronounced "horrible hack") we allow * ""%s"" to smuggle bad characters through. */ - if (0 == strcmp(fmp->printfc, "\"%s\"")) { + if (0 == strcmp(fmp.printfc.constData(), "\"%s\"")) { obuff = '"' + obuff + '"'; } *xcsv_file.stream << obuff; @@ -2170,13 +2152,7 @@ xcsv_replace_tokens(const QString& original) { // Don't do potentially expensive replacements if token prefix // isn't present; if (original.contains("__")) { - struct tm tm; time_t my_time = gpsbabel_time; - if (my_time == 0) { /* testo script ? */ - tm = *gmtime(&my_time); - } else { - tm = *localtime(&my_time); - } replacement.replace("__FILE__", xcsv_file.fname); replacement.replace("__VERSION__", my_time == 0 ? "" : gpsbabel_version); @@ -2203,21 +2179,11 @@ xcsv_replace_tokens(const QString& original) { void xcsv_data_write(void) { - time_t time; - struct tm tm; - /* reset the index counter */ waypt_out_count = 0; - time = gpsbabel_time; - if (time == 0) { /* testo script ? */ - tm = *gmtime(&time); - } else { - tm = *localtime(&time); - } - /* output prologue lines, if any. */ - for (auto line : xcsv_file.prologue) { + for (const auto& line : xcsv_file.prologue) { QString line_to_write = xcsv_replace_tokens(line); *xcsv_file.stream << line_to_write << xcsv_file.record_delimiter; } @@ -2233,7 +2199,7 @@ xcsv_data_write(void) } /* output epilogue lines, if any. */ - for (auto line : xcsv_file.epilogue) { + for (const auto& line : xcsv_file.epilogue) { QString line_to_write = xcsv_replace_tokens(line); *xcsv_file.stream << line_to_write << xcsv_file.record_delimiter; } diff --git a/csv_util.h b/csv_util.h index 64911af35..25925194f 100644 --- a/csv_util.h +++ b/csv_util.h @@ -63,39 +63,47 @@ void xcsv_file_init(void); void -xcsv_prologue_add(QString); +xcsv_prologue_add(const QString&); void -xcsv_epilogue_add(QString); +xcsv_epilogue_add(const QString&); void -xcsv_ifield_add(const char*, const char*, const char*); +xcsv_ifield_add(const QString&, const QString&, const QString&); void -xcsv_ofield_add(const char*, const char*, const char*, int options); +xcsv_ofield_add(const QString&, const QString&, const QString&, unsigned options); void xcsv_destroy_style(void); QString -xcsv_get_char_from_constant_table(QString key); +xcsv_get_char_from_constant_table(const QString& key); /****************************************************************************/ /* types required for various xcsv functions */ /****************************************************************************/ /* something to map fields to waypts */ -#define OPTIONS_NODELIM 1 -#define OPTIONS_ABSOLUTE 2 -#define OPTIONS_OPTIONAL 3 -typedef struct field_map { - queue Q; - const char* key; - const char* val; - const char* printfc; - int hashed_key; - int options; -} field_map_t; +#define OPTIONS_NODELIM 1U +#define OPTIONS_ABSOLUTE 2U +#define OPTIONS_OPTIONAL 4U +struct field_map { +public: + // We use QByteArrays because consumers want char* data and QByteArrays supply this through constData(). + // If we used QStrings, then we would have to convert to QByteArrays to get the char* data. + // If we use char* then we have to manage memory allocation/deallocation. + // TODO: when consumers use QStrings then we can store QStrings instead of QByteArrays. + QByteArray key; + QByteArray val; + QByteArray printfc; + int hashed_key{0}; + unsigned options{0}; + + field_map() = default; + field_map(const QByteArray& k, const QByteArray& v, const QByteArray& p, int hk) : key{k},val{v},printfc{p},hashed_key{hk} {} + field_map(const QByteArray& k, const QByteArray& v, const QByteArray& p, int hk, unsigned o) : key{k},val{v},printfc{p},hashed_key{hk},options{o} {} +}; /* something to map config file constants to chars */ typedef struct char_map { @@ -125,18 +133,13 @@ class XcsvFile { QStringList epilogue; QString field_delimiter; /* comma, quote, etc... */ - QString field_encloser; /* doublequote, etc... */ + QString field_encloser; /* doublequote, etc... */ QString record_delimiter; /* newline, c/r, etc... */ QString badchars; /* characters we never write to output */ - queue ifield; /* input field mapping */ - queue* ofield; /* output field mapping */ - QList ifields; - QList ofields; - - int ifield_ct; /* actual # of ifields */ - int ofield_ct; /* actual # of ofields */ + QList ifields; /* input field mapping */ + QList ofields; /* output field mapping */ gpsbabel::File* file; QTextStream* stream; diff --git a/xcsv.cc b/xcsv.cc index d93aec206..55e91b22d 100644 --- a/xcsv.cc +++ b/xcsv.cc @@ -23,9 +23,13 @@ */ -#include -#include -#include +#include // for QByteArray +#include // for QHash +#include // for QString +#include // for QStringList +#include // for QTextCodec +#include // for QTextStream +#include // for qPrintable #include #include @@ -110,8 +114,6 @@ char_map_t xcsv_char_table[] = { void xcsv_destroy_style(void) { - queue* elem, *tmp; - field_map_t* fmp; /* * If this xcsv_file struct came from a file we can free it all. @@ -125,45 +127,8 @@ xcsv_destroy_style(void) xcsv_file.epilogue.clear(); /* destroy the ifields */ - QUEUE_FOR_EACH(&xcsv_file.ifield, elem, tmp) { - fmp = reinterpret_cast(elem); - if (fmp->key) { - xfree(fmp->key); - } - if (fmp->val) { - xfree(fmp->val); - } - if (fmp->printfc) { - xfree(fmp->printfc); - } - if (elem) { - xfree(elem); - } - } - - /* destroy the ofields, if they are not re-mapped to ifields. */ - if (xcsv_file.ofield != &xcsv_file.ifield) { - QUEUE_FOR_EACH(xcsv_file.ofield, elem, tmp) { - fmp = reinterpret_cast(elem); - if (fmp->key) { - xfree(fmp->key); - } - if (fmp->val) { - xfree(fmp->val); - } - if (fmp->printfc) { - xfree(fmp->printfc); - } - if (elem) { - xfree(elem); - } - } - - if (xcsv_file.ofield) { - xfree(xcsv_file.ofield); - } - } xcsv_file.ifields.clear(); + /* destroy the ofields */ xcsv_file.ofields.clear(); /* other alloc'd glory */ @@ -185,7 +150,7 @@ xcsv_destroy_style(void) // Given a keyword of "COMMASPACE", return ", ". QString -xcsv_get_char_from_constant_table(QString key) +xcsv_get_char_from_constant_table(const QString& key) { static QHash substitutions; if (substitutions.empty()) { @@ -202,7 +167,7 @@ xcsv_get_char_from_constant_table(QString key) // Remove outer quotes. // Should probably be in csv_util. -static QString dequote(QString in) { +static QString dequote(const QString& in) { QString r = in.simplified(); if (r.startsWith("\"")) r = r.mid(1); if (r.endsWith("\"")) r.chop(1); @@ -347,12 +312,9 @@ xcsv_parse_style_line(QString line) // The key ("LAT_DIR") should never contain quotes. - const char* key = xstrdup(tokens[0].simplified()); - QString s1 = dequote(tokens[1]); - char* val = xstrdup(s1); - - QString s2 = dequote(tokens[2]); - char* pfc = xstrdup(s2); + const QString key = tokens[0].simplified(); + const QString val = dequote(tokens[1]); + const QString pfc = dequote(tokens[2]); xcsv_ifield_add(key, val, pfc); } else @@ -362,20 +324,16 @@ xcsv_parse_style_line(QString line) // change the world on ifield vs ofield format later.. // if (op == "OFIELD") { - int options = 0; + unsigned options = 0; // Note: simplifieid() has to run after split(). if (tokens.size() < 3) { Fatal() << "Invalid OFIELD line: " << tokenstr; } // The key ("LAT_DIR") should never contain quotes. - const char *key = xstrdup(tokens[0].simplified()); - - QString s1 = dequote(tokens[1]); - char *val = xstrdup(s1); - - QString s2 = dequote(tokens[2]); - const char* pfc = xstrdup(s2); + const QString key = tokens[0].simplified(); + const QString val = dequote(tokens[1]); + const QString pfc = dequote(tokens[2]); // This is pretty lazy way to parse write options. // They've very rarely used, so we'll go for simple. @@ -422,12 +380,8 @@ xcsv_read_style(const char* fname) } /* if we have no output fields, use input fields as output fields */ - if (xcsv_file.ofield_ct == 0) { - if (xcsv_file.ofield) { - xfree(xcsv_file.ofield); - } - xcsv_file.ofield = &xcsv_file.ifield; - xcsv_file.ofield_ct = xcsv_file.ifield_ct; + if (xcsv_file.ofields.isEmpty()) { + xcsv_file.ofields = xcsv_file.ifields; } gbfclose(fp); } @@ -446,12 +400,8 @@ xcsv_read_internal_style(const char* style_buf) xcsv_parse_style_buff(style_buf); /* if we have no output fields, use input fields as output fields */ - if (xcsv_file.ofield_ct == 0) { - if (xcsv_file.ofield) { - xfree(xcsv_file.ofield); - } - xcsv_file.ofield = &xcsv_file.ifield; - xcsv_file.ofield_ct = xcsv_file.ifield_ct; + if (xcsv_file.ofields.isEmpty()) { + xcsv_file.ofields = xcsv_file.ifields; } } -- 2.30.2